#include <getopt.hpp>
#include <iostream>

static bool check(struct option *opts){
    return opts->name || opts->has_arg || opts->flag || opts->val;
}

static const std::string EMPTY;

getoptions::getoptions(int argc,char **argv,struct option *longopts)
{
    std::string optstr=":";
    for (struct option *opts=longopts;opts && check(opts);opts++){
        optstr.push_back((char)opts->val);
        if (opts->has_arg==required_argument){
            optstr.push_back(':');
        }else if(opts->has_arg==optional_argument){
            optstr.append("::");
        }
        mOptions.insert(std::pair<int,LongOpt>(opts->val,LongOpt(*opts)));
    }
    mError=0;
    int ch,lidx;
    while((ch=getopt_long(argc,argv,optstr.c_str(),longopts,&lidx))!=-1){
        option(ch,optarg,optopt);
    }
    for(int i=optind;i<argc;i++){
        non_option(argv[i]);
    }
}

getoptions::~getoptions()
{

}

int getoptions::option(int ch, const char *arg,int optch)
{
    std::map<int,LongOpt>::iterator iter;
    if(ch=='?'){
        std::cerr<<"Unrecognized option -"<<(char)optch<<'\n';
        mError=1;
        return -1;
    }
    if (ch==':'){
        iter=mOptions.find(optch);
        std::cerr<<"Missing parameter for option -"<<(char)optch;
        if (iter!=mOptions.end()){
            std::cerr<<" or --"<<iter->second.name;
        }
        std::cerr<<'\n';
        mError=1;
        return -1;
    }
    if ((iter=mOptions.find(ch))!=mOptions.end()){
        if (iter->second.has_arg==no_argument || (iter->second.has_arg==optional_argument && arg==NULL)){
            mArgument.insert(std::make_pair(iter->second.name,EMPTY));
        }else{
            mArgument.insert(std::make_pair(iter->second.name,std::string(arg)));
        }
    }
    return 0;
}

int getoptions::non_option(const char *arg)
{
    mNonoptArgument.push_back(std::string(arg));
    return 0;
}
